package com.yiyuan.app.controller;

import com.alibaba.fastjson.JSON;
import com.alipay.api.internal.util.AlipaySignature;
import com.yiyuan.app.config.AliPayProperties;
import com.yiyuan.app.config.WxPayProperties;
import com.yiyuan.app.entity.po.TradeRecordAlipayDetailPO;
import com.yiyuan.app.service.PayNotifyService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/payNotify")
@AllArgsConstructor
public class PayNotifyController {

    private final WxPayProperties properties;

    private final AliPayProperties aliPayProperties;

    private final RSAAutoCertificateConfig config;

    private final PayNotifyService payNotifyService;

    @ApiIgnore
    @PostMapping("/wxNotify")
    public String wxNotify(HttpServletRequest request) {
        log.info("==微信支付回调开始==");
        Map<String, String> map = new HashMap<>();
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        try {
            InputStream in = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            StringBuilder param = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                param.append(line);
            }
            String callBackParam = param.toString();
            // 签名的验证及解密
            // 构建request，传入必要参数
            RequestParam requestParam = new RequestParam
                    .Builder()
                    .serialNumber(request.getHeader("Wechatpay-Serial"))
                    .nonce(request.getHeader("Wechatpay-Nonce"))
                    .signature(request.getHeader("Wechatpay-Signature"))
                    .signType(request.getHeader("Wechatpay-Signature-Type"))
                    .timestamp(request.getHeader("Wechatpay-Timestamp"))
                    .body(callBackParam)
                    .build();
            // 从notification中获取解密报文
            NotificationParser parser = new NotificationParser(config);
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            log.info("微信回调结果解密，transaction={}", JSON.toJSONString(transaction));
            payNotifyService.wxPayNotify(transaction);
        } catch (Exception e) {
            log.error("微信支付结果通知回调接口异常：{}", e);
            map.put("code", "FAIL");
            map.put("message", "失败");
            return JSON.toJSONString(map);
        }
        return JSON.toJSONString(map);
    }


    @ApiIgnore
    @PostMapping("/wxRefundNotify")
    public String wxRefundNotify(HttpServletRequest request) {
        log.info("==微信退款回调开始==");
        Map<String, String> map = new HashMap<>();
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        try {
            InputStream in = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            StringBuilder param = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                param.append(line);
            }
            String callBackParam = param.toString();
            log.info("微信退款回调参数={}" + callBackParam);
            // 签名的验证及解密
            // 构建request，传入必要参数
            RequestParam requestParam = new RequestParam
                    .Builder()
                    .serialNumber(request.getHeader("Wechatpay-Serial"))
                    .nonce(request.getHeader("Wechatpay-Nonce"))
                    .signature(request.getHeader("Wechatpay-Signature"))
                    .signType(request.getHeader("Wechatpay-Signature-Type"))
                    .timestamp(request.getHeader("Wechatpay-Timestamp"))
                    .body(callBackParam)
                    .build();
            // 从notification中获取解密报文
            NotificationParser parser = new NotificationParser(config);
            RefundNotification transaction = parser.parse(requestParam, RefundNotification.class);
            payNotifyService.wxRefundNotify(transaction);
        } catch (Exception e) {
            log.error("微信退款结果通知回调接口异常：{}", e);
            map.put("code", "FAIL");
            map.put("message", "失败");
            return JSON.toJSONString(map);
        }
        return JSON.toJSONString(map);
    }

    @ApiIgnore
    @PostMapping("/aliNotify")
    public String aliNotify(HttpServletRequest request) {
        log.info("==支付宝支付回调开始==");
        try {
            //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
            Map<String, String> params = new HashMap<>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }
            //公钥证书验签示例代码
            boolean signVerified = AlipaySignature.rsaCertCheckV1(params, aliPayProperties.getAliPayPublicCertPath(), "UTF-8", "RSA2");
            if (signVerified) {
                params.remove("version");
                TradeRecordAlipayDetailPO transaction = JSON.parseObject(JSON.toJSONString(params), TradeRecordAlipayDetailPO.class);
                if (transaction.getAppId().equals(aliPayProperties.getAppId())) {
                    payNotifyService.aliPayNotify(transaction);
                } else {
                    log.error("支付宝支付结果通知appId不正确：{}", transaction.getAppId());
                }
                return "success";
            } else {
                log.error("支付宝支付结果验签失败");
                return "fail";
            }
        } catch (Exception e) {
            log.error("支付宝支付结果通知回调接口异常：{}", e);
            return "fail";
        }
    }
}
